import tool.ListNode;

import java.util.*;

/**
 * 给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为：node_1, node_2, node_3, ... 。
 * 每个节点都可能有下一个更大值（next larger value）：对于 node_i，如果其 next_larger(node_i) 是 node_j.val，那么就有 j > i 且  node_j.val > node_i.val，而 j 是可能的选项中最小的那个。如果不存在这样的 j，那么下一个更大值为 0 。
 * 返回整数答案数组 answer，其中 answer[i] = next_larger(node_{i+1}) 。
 * 注意：在下面的示例中，诸如 [2,1,5] 这样的输入（不是输出）是链表的序列化表示，其头节点的值为 2，第二个节点值为 1，第三个节点值为 5 。
 * <p>
 * 示例 1：
 * 输入：[2,1,5]
 * 输出：[5,5,0]
 * <p>
 * 示例 2：
 * 输入：[2,7,4,3,5]
 * 输出：[7,0,5,5,0]
 * <p>
 * 示例 3：
 * 输入：[1,7,5,1,9,2,5,1]
 * 输出：[7,9,9,9,0,5,0,0]
 * <p>
 * 提示：
 * 对于链表中的每个节点，1 <= node.val <= 10^9
 * 给定列表的长度在 [0, 10000] 范围内
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/next-greater-node-in-linked-list
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */

/**
 * 单调递减栈
 */
public class Q01019m {
    public int[] nextLargerNodes(ListNode head) {
        if (head == null) return new int[0];
        Deque<Integer> stack = new LinkedList<>();
        List<Pair> list = new ArrayList<>();
        int idx = 0;
        while (head != null) {
            Pair curr;
            while (stack.size() > 0 && head.val > (curr = list.get(stack.peek())).node.val) {
                stack.pop();
                curr.nv = head.val;
            }
            stack.push(idx);
            list.add(new Pair(head));
            head = head.next;
            idx++;
        }
        int[] ans = new int[idx];
        for (int i = 0; i < ans.length; i++) {
            ans[i] = list.get(i).nv;
        }
        return ans;
    }

    /**
     * 当前节点和其下一个较大值的组合
     */
    private class Pair {
        private ListNode node;
        private int nv;

        public Pair(ListNode node) {
            this.node = node;
        }
    }

    /**
     * 使用map存储链表节点和其下一个较大值
     *
     * @param head
     * @return
     */
    public int[] nextLargerNodes1(ListNode head) {
        if (head == null) return new int[0];
        Map<ListNode, Integer> map = new HashMap<>();
        Deque<ListNode> stack = new LinkedList<>();
        ListNode curr = head;
        int idx = 0;
        while (curr != null) {
            while (stack.size() > 0 && curr.val > stack.peek().val) {
                map.put(stack.pop(), curr.val);
            }
            stack.push(curr);
            curr = curr.next;
            idx++;
        }
        int[] ans = new int[idx];
        idx = 0;
        while (head != null) {
            ans[idx++] = map.getOrDefault(head, 0);
            head = head.next;
        }
        return ans;
    }
}
